package caro.app.business;
import caro.app.protocolprovider.*;
import caro.app.protocolprovider.chat.ChatProtocolProcessing;
import caro.app.protocolprovider.chat.SendMessagePro;
import caro.app.service.LoginService;
import java.io.*;
import java.net.*;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Class UserManagementImpl
 * @author Thanh Nhan
 * @Since Aug 14, 2011
 * @Version 1.0
 */
public class UserManagementImpl implements LoginService{
    private static final String USER_FILE_PATH = "users.mc";
    private static final String BLANK = " ";
    private BufferedReader br = null;
    private Socket client;
    private PlayerManagement players = null;
    private List<Session> sessions = null;
    private static final Logger logger = Logger.getLogger(UserManagementImpl.class.getName()) ;
    //private ProtocolProcessing protocolProvider = null;
    public UserManagementImpl(Socket client, PlayerManagement players, List<Session> sessions){
        this.client = client;
        this.players = players;
        this.sessions = sessions;
        //protocolProvider = new ProtocolProcessing();
    }
    
    private boolean login(String username, String password){
        String str = username.concat(BLANK).concat(password);
        try {
            br = new BufferedReader(new FileReader(USER_FILE_PATH));
            String line = br.readLine();
            while(line != null && !line.equals(str)){
                line = br.readLine();
            }
            return (null != line);
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        } finally{
            if(br != null){
                try{
                    br.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void run() {
        
        PrintWriter pw = null;
        BufferedReader br = null;
        
        try {
            br = new BufferedReader(new InputStreamReader(client.getInputStream()));
            pw = new PrintWriter(client.getOutputStream());
            while(true){
                //Lay tin nhan tu client
                String message = br.readLine();
                String protocol = ProtocolProcessing.getProtocol(message);
                logger.log(Level.INFO, "Giao thuc vua nhan: ".concat(protocol));
                //Goi thong diep login
                if(ProtocolProcessing.AUTH.equals(protocol)){
                    AuthClientPro authInfo = ProtocolProcessing.explainAuth(message);
                    boolean loginSuccess = login(authInfo.username, authInfo.password);
                    if(loginSuccess){
                        players.addPlayer(new Player(client, authInfo.username));
                        
                        //Lay 2 danh sach nguoi dung ban va nguoi dung roi
                        List<String> free = new LinkedList<String>(); 
                        List<String> busy = new LinkedList<String>(); 
                        
                        //Goi quang ba rang nguoi choi username da login vao
                        Iterator<Player> iterPlayers = players.getList().iterator();
                        while(iterPlayers.hasNext()){
                            Player player = iterPlayers.next();
                            
                            if(!Session.findPlayer(player, sessions))
                                free.add(player.getName());
                            else
                                busy.add(player.getName());
                            if(player.getName().equals(authInfo.username)) continue;
                            PrintWriter pw2 = new PrintWriter(player.getSocket().getOutputStream());
                            pw2.println(ProtocolProcessing.getNew(authInfo.username));
                            pw2.flush();
                            logger.log(Level.INFO, "Goi tin nhan den ".concat(player.getSocket().getInetAddress().toString())
                                    .concat("; Giao thuc: ".concat(ProtocolProcessing.getNew(authInfo.username))));
                            
                        }
                        //Goi hai danh sach nay cho username
                        PrintWriter pw2 = new PrintWriter(client.getOutputStream());
                        pw2.println(ProtocolProcessing.getLoginSuccess(free, busy));
                        pw2.flush();
                        logger.log(Level.INFO, "Goi tin nhan den ".concat(client.getInetAddress().toString())
                                .concat("; Giao thuc: ".concat(ProtocolProcessing.getLoginSuccess(free, busy))));
                        
                    }else{
                        logger.log(Level.INFO, "Goi thong bao dang nhap that bai. Giao thuc: ".concat(ProtocolProcessing.getLoginFail()));
                        pw.println(ProtocolProcessing.getLoginFail());
                        pw.flush();
                    }
                //Goi thong diep yeu cau choi voi nguoi choi username
                }else if(ProtocolProcessing.PLAY_REQUEST.equals(protocol)){
                    PlayRequestPro requestInfo = ProtocolProcessing.explainPlayRequest(message);
                    //Goi tiep yeu cau nay den username
                    String username = requestInfo.username;
                    //Tim username nay
                    Player tmpOpponent = players.findPlayer(username);
                    if(tmpOpponent != null){
                        Player myPlayer = players.findPlayer(client);
                        if(myPlayer != null){
                            PrintWriter pw2 = new PrintWriter(tmpOpponent.getSocket().getOutputStream());
                            pw2.println(ProtocolProcessing.getPlayRequest(myPlayer.getName()));
                            pw2.flush();
                        }
                    }
                //Client da chap nhan yeu cau choi cua username
                }else if(ProtocolProcessing.ACCEPT.equals(protocol)){
                    AcceptClientPro acceptInfo = ProtocolProcessing.explainAccept(message);
                    //Tim nguoi choi
                    Player myPlayer = players.findPlayer(client);
                    Player opponent = players.findPlayer(acceptInfo.username);
                    if(myPlayer != null && opponent != null){
                        //Thong bao bat dau cuoc choi cho ca hai
                        //Ai la nguoi moi choi, gia tri con co la 0, duoc phep di truoc
                        String line = ProtocolProcessing.getStart(opponent.getName(), 1);
                        opponent.setCheckValue(1);
                        PrintWriter pw2 = new PrintWriter(myPlayer.getSocket().getOutputStream());
                        pw2.println(line);
                        pw2.flush();
                        line = ProtocolProcessing.getStart(myPlayer.getName(), 0);
                        myPlayer.setCheckValue(0);
                        pw2 = new PrintWriter(opponent.getSocket().getOutputStream());
                        pw2.println(line);
                        pw2.flush();
                        //Tao session
                        sessions.add(new Session(myPlayer, opponent, 0));
                        //Thong bao quang ba rang hai nguoi choi nay da ban
                        Iterator<Player> iterPlayers = players.getList().iterator();
                        while(iterPlayers.hasNext()){
                            Player player = iterPlayers.next();
                            
                            pw2 = new PrintWriter(player.getSocket().getOutputStream());
                            pw2.println(ProtocolProcessing.getBusy(myPlayer.getName(), opponent.getName()));
                            pw2.flush();
                        }
                    }
                //Client da tu choi yeu cau choi cua username
                }else if(ProtocolProcessing.REFUSE.equals(protocol)){
                    RefuseClientPro refureInfo = ProtocolProcessing.explainRefuse(message);
                    Player opponent = players.findPlayer(refureInfo.username);
                    Player myPlayer = players.findPlayer(client);
                    if(opponent != null && myPlayer != null){
                        PrintWriter pw2 = new PrintWriter(opponent.getSocket().getOutputStream());
                        pw2.println(ProtocolProcessing.getRefuse(myPlayer.getName()));
                        pw2.flush();
                    }
                //Client goi mot nuoc co
                }else if(ProtocolProcessing.CHECK.equals(protocol)){
                    CheckCellPro checkInfo = ProtocolProcessing.explainCheckCell(message);
                    Player opponent = players.findPlayer(checkInfo.username);
                    Player myPlayer = players.findPlayer(client);
                    if(opponent != null && myPlayer != null){
                        
                        Iterator<Session> iterSessions = sessions.iterator();
                        while(iterSessions.hasNext()){
                            Session session = iterSessions.next();
                            Player tmp = session.getOpponent(myPlayer.getName());
                            if(tmp != null && tmp.getName().equals(opponent.getName())){
                                //Check nuoc co nay vao board
                                session.setCellValue(checkInfo.row, checkInfo.column, checkInfo.value);
                                //Kiem tra thang thua
                                char win = session.getBoard().testWin(checkInfo.row, checkInfo.column);
                                if(win != Board.NOT_WIN){
                                    //Neu thang thua xay ra
                                    int[] firstCellWin = session.getBoard().getFirstCellWin(checkInfo.row, checkInfo.column);
                                    //Goi cho nguoi that bai
                                    PrintWriter pw2 = new PrintWriter(opponent.getSocket().getOutputStream());
                                    pw2.println(ProtocolProcessing.getLost(firstCellWin[0], firstCellWin[1], 
                                            win, checkInfo.value));
                                    pw2.flush();
                                    //Goi cho nguoi chien thang
                                    pw2 = new PrintWriter(myPlayer.getSocket().getOutputStream());
                                    pw2.println(ProtocolProcessing.getWin(firstCellWin[0], firstCellWin[1], 
                                            win, checkInfo.value));
                                    pw2.flush();
                                }else{
                                    //Neu chua thang thua
                                    PrintWriter pw2 = new PrintWriter(opponent.getSocket().getOutputStream());
                                    pw2.println(ProtocolProcessing.getCheckCell(myPlayer.getName(), checkInfo.row, 
                                            checkInfo.column, checkInfo.value));
                                    pw2.flush();
                                }
                                break;
                            }
                        }
                        
                    }
                //Client thoat
                }else if(ProtocolProcessing.EXIT.equals(protocol)){
                    ExitClientPro exitInfo = ProtocolProcessing.explainExit(message);
                    Player myPlayer = players.findPlayer(client);
                    //Thong bao quang ba nguoi choi nay da roi
                    
                    Iterator<Player> iterPlayers = players.getList().iterator();
                    while(iterPlayers.hasNext()){
                        Player player = iterPlayers.next();
                        if(!player.getName().equals(myPlayer.getName())){
                            PrintWriter pw2 = new PrintWriter(player.getSocket().getOutputStream());
                            pw2.println(ProtocolProcessing.getLeave(myPlayer.getName(), exitInfo.username));
                            pw2.flush();
                            pw2.println(ProtocolProcessing.getExit(myPlayer.getName()));
                            pw2.flush();
                        }
                    }
                    
                    //Remove ra khoi danh sach
                    if(!"NULL".equals(exitInfo.username)){
                        Player opponent = players.findPlayer(exitInfo.username);
                        sessions.remove(new Session(myPlayer, opponent, 0));
                        sessions.remove(new Session(opponent, myPlayer, 0));
                        //players.removePlayer(opponent);
                    }
                    players.removePlayer(myPlayer);
                    //Now close socket
                    client.close();
                    //exit
                    break;
                }
                //Client dung choi
                else if(ProtocolProcessing.LEAVE.equals(protocol)){
                    LeavePro leave = ProtocolProcessing.explainLeave(message);
                    //Thong bao quang ba 2 client da roi
                    
                    Iterator<Player> iterPlayers = players.getList().iterator();
                    while(iterPlayers.hasNext()){
                        Player player = iterPlayers.next();
                        if(!player.getName().equals(leave.username1)){
                            PrintWriter pw2 = new PrintWriter(player.getSocket().getOutputStream());
                            pw2.println(ProtocolProcessing.getLeave(leave.username1, leave.username2));
                            pw2.flush();
                        }
                    }
                    //Remove ra khoi danh sach
                    Player myPlayer = players.findPlayer(leave.username1);
                    Player opponent = players.findPlayer(leave.username2);
                    sessions.remove(new Session(myPlayer, opponent, 0));
                    sessions.remove(new Session(opponent, myPlayer, 0));
                }else if(ChatProtocolProcessing.SEND_MESSAGE.equals(protocol)){
                    SendMessagePro sendPro = ChatProtocolProcessing.explainSendMessagePro(message);
                    Player opponent = players.findPlayer(sendPro.username);
                    Player myPlayer = players.findPlayer(client);
                    PrintWriter writer = new PrintWriter(opponent.getSocket().getOutputStream());
                    writer.println(ChatProtocolProcessing.getSendMessagePro(myPlayer.getName(), sendPro.content));
                    writer.flush();
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            pw.close();
        }
    }
}
